package se.webbzon.boltzmann.game.object.waypoint;


public enum PathProgramEnum {
	
	STATIC(new Static()),
	ONE_WAY(new OneWay()), 
	ONE_WAY_WARP(new OneWayWarp()), 
	ONE_WAY_WARP_PAUSE(new OneWayWarpPause()), 
	ONE_WAY_WARP_PAUSE_TWICE(new OneWayWarpPauseTwice()),
	BIDIRECTIONAL(new Bidirectional()), 
	BIDIRECTIONAL_PAUSE(new BidirectionalPause()), 
	BIDIRECTIONAL_PAUSE_TWICE(new BidirectionalPauseTwice());
	
	// The path program associated with this enumeration
	private final PathProgram program;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new path program enumeration associated to 
	 * the given path program. **/
	private PathProgramEnum(PathProgram program) {
		this.program = program;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the program associated with this enumeration. **/
	public PathProgram getProgram() {
		return program;
	}
	
	/*============================================================
	Private 
	============================================================*/
	
	/** Static **/
	private static final class Static implements PathProgram {

		@Override public double run(PathMovable movable) {
			return 0;
		}
		
	}
	
	/** One way **/
	private static class OneWay implements PathProgram {

		@Override public double run(PathMovable movable) {
			return movable.pos() / (double) movable.getCycleDuration();
		}
		
	}
	
	/** One way with warp **/
	private static class OneWayWarp extends OneWay {

		@Override public double run(PathMovable movable) {
			final double position = super.run(movable);
			if (movable.isPlaying() && position == 1)
				movable.seek(0);
			else if (movable.isRewinding() && position == 0)
				movable.seek(1);
			return position;	
		}
		
	}
	
	/** One way with warp and end pause **/
	private static final class OneWayWarpPause extends OneWayWarp {

		@Override public double run(PathMovable movable) {
			final double position = super.run(movable);
			return Math.min(1,position / 0.9);	
		}
		
	}
	
	/** One way with warp, start pause and end pause **/
	private static final class OneWayWarpPauseTwice extends OneWayWarp {

		@Override public double run(PathMovable movable) {
			final double position = super.run(movable);
			return Math.max(0,Math.min(1,(position-0.1) / 0.8));	
		}
		
	}
	
	/** Bidirectional **/
	private static class Bidirectional implements PathProgram {

		@Override public double run(PathMovable movable) {
			final double position = 
					movable.pos() / (double) movable.getCycleDuration();
			if (movable.isPlaying() && position >= 0.5)
				movable.rewind();
			else if (movable.isRewinding() && position <= 0)
				movable.play();
			return 2*position;
		}
		
	}
	
	/** Bidirectional with end pause **/
	private static final class BidirectionalPause extends Bidirectional {

		@Override public double run(PathMovable movable) {
			final double position = super.run(movable);
			return Math.min(1,position / 0.90);
		}
		
	}
	
	/** Bidirectional with start and end pause **/
	private static final class BidirectionalPauseTwice extends Bidirectional {

		@Override public double run(PathMovable movable) {
			final double position = super.run(movable);
			return Math.max(0,Math.min(1,(position-0.1) / 0.8));
		}
		
	}

}
